package org.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.example.config.RabbitMQConfig;
import org.example.enums.BizCodeEnum;
import org.example.enums.CouponStateEnum;
import org.example.enums.ProductOrderStateEnum;
import org.example.enums.StockTaskStateEnum;
import org.example.exception.BizException;
import org.example.feign.ProductOrderFeignService;
import org.example.interceptor.LoginInterceptor;
import org.example.mapper.CouponRecordMapper;
import org.example.mapper.CouponTaskMapper;
import org.example.model.*;
import org.example.request.LockCouponRecordRequest;
import org.example.service.CouponRecordService;
import org.example.util.JsonData;
import org.example.vo.CouponRecordVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CouponRecordServiceImpl implements CouponRecordService {

    @Autowired
    private CouponRecordMapper couponRecordMapper;

    @Autowired
    private CouponTaskMapper couponTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private ProductOrderFeignService orderFeignService;

    /**
     * 分页查询个人优惠券记录
     */
    @Override
    public PageResult page(int page, int size) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        Long userId = loginUser.getId();
        Page<CouponRecordDO> pageInfo = new Page<>(page, size);
        Page<CouponRecordDO> recordDOPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>()
                .eq("user_id", userId)
                .orderByDesc("create_time"));
        long totalRecord = recordDOPage.getTotal();
        long totalPage = recordDOPage.getPages();
        List<CouponRecordVO> voList = recordDOPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList());
        return new PageResult(totalRecord, totalPage, voList);
    }

    /**
     * 查询优惠券详情
     */
    @Override
    public CouponRecordVO findById(Long recordId) {
        Long userId = LoginInterceptor.threadLocal.get().getId();
        CouponRecordDO recordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>()
                .eq("id", recordId)
                .eq("user_id", userId));
        CouponRecordVO recordVO = beanProcess(recordDO);
        return recordVO;
    }

    /**
     * 锁定优惠券记录
     */
    @Override
    public JsonData lockCouponRecords(LockCouponRecordRequest recordRequest) {
        // 获取用户id
        Long userId = LoginInterceptor.threadLocal.get().getId();
        // 获取优惠券记录id列表
        List<Long> couponRecordIds = recordRequest.getLockCouponRecordIds();
        // 获取订单号
        String orderOutTradeNo = recordRequest.getOrderOutTradeNo();
        // 批量更新优惠券记录表（NEW->USED）
        int updateRows = couponRecordMapper.insertLockUseStateBatch(userId, CouponStateEnum.USED.name(), couponRecordIds);
        // 获取锁定优惠券记录对象的集合
        List<CouponTaskDO> couponTaskDOList = couponRecordIds.stream().map(obj -> {
            CouponTaskDO taskDO = new CouponTaskDO();
            taskDO.setCouponRecordId(obj);
            taskDO.setCreateTime(new Date());
            taskDO.setOutTradeNo(orderOutTradeNo);
            taskDO.setLockState(StockTaskStateEnum.LOCK.name());
            return taskDO;
        }).collect(Collectors.toList());
        // 批量插入到锁定优惠券表
        int insertRows = couponTaskMapper.insertCouponTaskBatch(couponTaskDOList);
        // 比较更新条数，优惠券记录id的长度=批量更新长度=批量插入长度
        if (couponRecordIds.size() == updateRows && updateRows == insertRows) {
            //发送消息
            for (CouponTaskDO taskDO : couponTaskDOList) {
                CouponRecordMessage message = new CouponRecordMessage();
                message.setTaskId(taskDO.getId());
                message.setOutTradeNo(taskDO.getOutTradeNo());
                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getCouponReleaseDelayRoutingKey(),
                        message);
                log.info("发送消息成功: {}", message.toString());
            }
            return JsonData.buildSuccess();
        } else {
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }
//        return null;
    }

    /**
     * 解锁优惠券记录
     * 1)查看task工作单是否存在
     * 2)查看订单状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean releaseCouponRecord(CouponRecordMessage recordMessage) {
        //1、查询task工作单是否存在
//        CouponTaskDO taskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>().
//                eq("id", recordMessage.getTaskId()));
        CouponTaskDO taskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>()
                .eq("id", recordMessage.getTaskId()));
        //2、task工作单不存在，成功消费
        if (taskDO == null) {
            log.warn("订单不存在，消息:{}", recordMessage);
            return true;
        }
        //3、判断task的状态是否为LOCK
        if (taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
            //4、查询订单状态
            JsonData jsonData = orderFeignService.queryProductOrderState(recordMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {
                //5、如果订单状态为NEW，返回给消息队列，重新投递
                String state = jsonData.getData().toString();
                if (state.equalsIgnoreCase(ProductOrderStateEnum.NEW.name())) {
                    //优惠券使用后怎么还可以是新的呢？给爷回去重新投递吧
                    log.warn("订单状态为NEW，返回给消息队列，重新投递，message:{}", recordMessage);
                    return false;
                }
                //6、如果是已经支付PAY，修改task状态为FINISH，消费完成
                if (state.equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {
                    taskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    couponTaskMapper.update(taskDO, new QueryWrapper<CouponTaskDO>()
                            .eq("id", recordMessage.getTaskId()));
                    log.info("订单已支付，task状态修改为FINISH，message:{}", recordMessage);
                    return true;
                }

            }
            //7、订单不存在，或者订单被取消，确认消息，修改task状态为CANCEL，恢复优惠券使用记录为NEW
            log.warn("订单不存在，或者订单被取消，确认消息，修改task状态为CANCEL，恢复优惠券使用记录为NEW，message:{}", recordMessage);
            //task状态设为CANCEL
            taskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            //更新
            couponTaskMapper.update(taskDO, new QueryWrapper<CouponTaskDO>().eq("id", recordMessage.getTaskId()));
            //恢复优惠券使用记录为NEW
            couponRecordMapper.updateState(taskDO.getCouponRecordId(), CouponStateEnum.NEW.name());
            return true;
        } else {
            //不为lock，释放
            log.warn("工作单状态不为LOCK，state={}，message={}", taskDO.getLockState(), recordMessage);
            return true;
        }
    }


    /**
     * 将couponRecordDO转为couponRecordVO
     */
    private CouponRecordVO beanProcess(CouponRecordDO couponRecordDO) {
        CouponRecordVO couponRecordVO = new CouponRecordVO();
        if (couponRecordDO != null) {
            BeanUtils.copyProperties(couponRecordDO, couponRecordVO);
            return couponRecordVO;
        }
        return null;
    }

}